package router

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"html/template"
	"io"
	"os"
	"runtime"
	"strings"
	"time"
	"turingApi/conf"
	"turingApi/internal/token"
	"turingApi/model"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"github.com/zxysilent/utils"
)

var funcMap template.FuncMap

func init() {
	funcMap = template.FuncMap{"str2html": Str2html, "str2js": Str2js, "date": Date, "md5": Md5}
}

// midRecover 恢复中间件
func midRecover(next echo.HandlerFunc) echo.HandlerFunc {
	return func(ctx echo.Context) error {
		defer func() {
			if r := recover(); r != nil {
				err, ok := r.(error)
				if !ok {
					err = fmt.Errorf("%v", r)
				}
				stack := make([]byte, 1<<10)
				length := runtime.Stack(stack, false)
				// stdlog.Println(string(stack[:length]))
				os.Stdout.Write(stack[:length])
				ctx.Error(err)
			}
		}()
		return next(ctx)
	}
}

// HTTPErrorHandler 全局错误捕捉
func HTTPErrorHandler(err error, ctx echo.Context) {
	if !ctx.Response().Committed {
		if he, ok := err.(*echo.HTTPError); ok {
			if he.Code == 404 {
				if strings.HasPrefix(ctx.Request().URL.Path, "/static") || strings.HasPrefix(ctx.Request().URL.Path, "/dist") {
					ctx.NoContent(404)
				} else if strings.HasPrefix(ctx.Request().URL.Path, "/api") || strings.HasPrefix(ctx.Request().URL.Path, "/adm") {
					ctx.JSON(utils.ErrSvr("系统错误", he.Message))
				} else {
					ctx.HTML(404, html404)
				}
			} else {
				ctx.JSON(utils.ErrSvr("系统错误", he.Message))
			}
		} else {
			ctx.JSON(utils.ErrSvr("系统错误", err.Error()))
		}
	}
}

// 跨越配置
var crosConfig = middleware.CORSConfig{
	AllowOrigins: []string{"*"},
	AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept, echo.HeaderAuthorization},
}

// TplRender is a custom html/template renderer for Echo framework
type TplRender struct {
	templates *template.Template
}

// Render renders a template document
func (t *TplRender) Render(w io.Writer, name string, data interface{}, ctx echo.Context) error {
	// 获取数据配置项
	if mp, is := data.(map[string]interface{}); is {
		mp["appjs"] = AppJsUrl
		mp["appcss"] = AppCssUrl
		mp["global"] = model.Gcfg()
	}
	//开发模式
	//每次强制读取模板
	//每次强制加载函数
	if conf.App.IsDev() {
		t.templates, _ = utils.LoadTmpl("./views", funcMap)
	}
	return t.templates.ExecuteTemplate(w, name, data)
}

// Str2html Convert string to template.HTML type.
func Str2html(raw string) template.HTML {
	return template.HTML(raw)
}

// Str2js Convert string to template.JS type.
func Str2js(raw string) template.JS {
	return template.JS(raw)
}

// Date Date
func Date(t time.Time, format string) string {
	return t.Format(format) //"2006-01-02 15:04:05"
}

// Md5 Md5
func Md5(str string) string {
	ctx := md5.New()
	ctx.Write([]byte(str))
	return hex.EncodeToString(ctx.Sum(nil))
}

// initRender 初始化模板和函数
func initRender() *TplRender {
	tpl, _ := utils.LoadTmpl("./views", funcMap)
	return &TplRender{
		templates: tpl,
	}
}

// midAuth 登录认证中间件
func midAuth(next echo.HandlerFunc) echo.HandlerFunc {
	return func(ctx echo.Context) error {
		tokenRaw := ctx.FormValue(conf.App.TokenKey) // query/form 查找 token
		if tokenRaw == "" {
			tokenRaw = ctx.Request().Header.Get(echo.HeaderAuthorization) // header 查找token
			if tokenRaw == "" {
				return ctx.JSON(utils.ErrToken("请重新登陆", "token为空"))
			}
		}
		auth := token.Auth{}
		err := auth.Decode(tokenRaw, conf.App.TokenSecret)
		if err != nil {
			return ctx.JSON(utils.ErrToken("请重新登陆", err.Error()))
		}
		// 验证通过，保存信息
		ctx.Set("auth", auth)
		ctx.Set("uid", auth.Id)
		ctx.Set("rid", auth.RoleId)
		// 后续流程
		return next(ctx)
	}
}

// html404 404错误页面
const html404 = `<!DOCTYPE html><html lang="en"><body>404 not found</body></html>`
